package com.ssc.reproguard

import com.ssc.reproguard.extension.ReproguardPluginExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File
import java.io.FileWriter
import java.util.concurrent.Callable
import java.util.concurrent.Executors

class ReproguardPlugin : Plugin<Project> {

    val RE_PROGUARD_CONFIG = "reProguardConfig"
    val GROUP ="ssc"
    val TASK_NAME = "reProguard"
    val LOCAL_PROPERTIES ="local.properties"
    val RETRACE_SH ="retrace.sh"

    override fun apply(target: Project) {
        val reProguardConfig =
            target.extensions.create(RE_PROGUARD_CONFIG, ReproguardPluginExtension::class.java)


        target.tasks.register(TASK_NAME) {
            group = GROUP

            // 获取 Android SDK 路径
            var retraceSh = project.rootProject.file(LOCAL_PROPERTIES)
                .readLines()
                .find { it.startsWith(RETRACE_SH) }
                ?.split("=")?.get(1)?.trim()

            if (retraceSh == null) {
                target.logger.error("请配置 retrace.sh 路径")
                return@register
            }
            println("retraceSh = ${retraceSh}")
            val osName = System.getProperty("os.name")
            if (osName?.contains("Windows") == true) {
                retraceSh = retraceSh.replace("\\\\", "\\")
                    .replace("\\:", ":")
            }
            val mapping =reProguardConfig.mappingFiles// project.rootProject.file("mapping")
            val errorFiles = reProguardConfig.errorFiles// project.rootProject.file("testError")
            val reFile = reProguardConfig.reFiles //project.rootProject.file("reFile")
            reFile.mkdirs()

            // 创建线程池
            val threadPool =
                Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
            val preTime = System.currentTimeMillis()
            // 创建任务列表
            val tasks = mutableListOf<Callable<Unit>>()


            var notMappingFile = File("${mapping}/mapping.txt")
            if(!notMappingFile.exists()){
                notMappingFile.writeText("自动生成一个mapping占位")
            }

            errorFiles.listFiles()?.forEach {
                tasks.add(Callable {
                    /**
                     * 根据版本生相应版本的文件夹，对错误日志进行分类
                     */
                    val fileVersion = extractVersionFromFile(it)
                    val outputVersionFile = File(reFile, fileVersion)
                    outputVersionFile.mkdirs()


                    target.logger.error("解混淆->" + it.name)
                    /**
                     *
                     * https://github.com/Guardsquare/proguard
                     * 执行 retrace.sh 命令
                     * 用于解混淆
                     */
                    var mappingFile = File("${mapping}/mapping-${fileVersion}.txt")
                    var isHaveMapping = true
                    if (!mappingFile.exists()) {
                        isHaveMapping =false
                        mappingFile = File("${mapping}/mapping.txt")
                    }
                    val command = listOf(
                        "$retraceSh",
                        "-verbose",
                        "${mappingFile}",
                        "${errorFiles}/${it.name}"
                    )
                    // 创建输出文件
                    val outputFile = File(outputVersionFile, "re-${it.name}")
                    // 创建 ProcessBuilder 实例
                    val processBuilder = ProcessBuilder(command)
                    processBuilder.redirectOutput(outputFile) // 将输出重定向到各自的文件
                    processBuilder.redirectErrorStream(true) // 合并标准输出和错误输出

                    try {
                        val process = processBuilder.start()

                        val exitCode = process.waitFor()

                        if (exitCode == 0) {
                            if(isHaveMapping){
                                project.logger.lifecycle("Retrace successful for ${outputFile.name}, output: ${outputFile.absolutePath}")
                            }else{
                                faile(exitCode,outputFile,"未找到mapping文件")
                                project.logger.error("Retrace failed for ${outputFile.name}, exit code: $exitCode")
                            }

                        } else {
                            faile(exitCode,outputFile)
                            project.logger.error("Retrace failed for ${outputFile.name}, exit code: $exitCode")
                        }
                    } catch (e: Exception) {
                        faile(-1,outputFile)
                        project.logger.error("Error while retracing ${outputFile.name}: ${e.message}")
                    }
                })
            }
            // 并行执行所有任务
            threadPool.invokeAll(tasks)
            threadPool.shutdown()
            val curTime = System.currentTimeMillis()
            target.logger.lifecycle("耗时:${curTime - preTime}ms")
        }

    }

    /**
     * 从混淆文件中提取版本号。
     * 假设版本号行的格式为 "应用版本 = V1.3.0"。
     */
    fun extractVersionFromFile(file: File): String {
        var version = "Unknown_Version" // 默认版本号
        file.forEachLine { line ->
            if (line.contains("应用版本")) {
                val curVersion = line.substringAfter("应用版本 = ").trim()

                if (version.isNotEmpty()) {
                    version = curVersion  // 例如：Version_V1.3.0
                    return@forEachLine
                }
            }
        }
        return version
    }

    fun faile( exitCode: Int, outputFile: File,message: String = "") {
        FileWriter(outputFile, true).use { writer ->
            if(message.isNotEmpty()){
                writer.appendLine(message)
            }
            writer.appendLine("\nCommand failed with exit code: $exitCode.")
        }
    }

}